package com.gmrz.util;

import com.gmrz.uaf.common.TLVTag;
import com.gmrz.uaf.common.UAFRuntimeException;
import com.gmrz.uaf.crypto.sm.SM3Utils;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.codec.binary.Base64;

import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Convert {

    public static byte[] toAscii(String str)
            throws UnsupportedEncodingException {
        return str.getBytes("US-ASCII");
    }

    public static String fromAscii(byte[] bytes)
            throws UnsupportedEncodingException {
        return new String(bytes, "US-ASCII");
    }

    public static byte[] toUtf8(String str)
            throws UnsupportedEncodingException {
        return str.getBytes("UTF-8");
    }

    public static String fromUtf8(byte[] bytes)
            throws UnsupportedEncodingException {
        return new String(bytes, "UTF-8");
    }

    public static void toBigEndian(int value, byte[] bytes, int offset) {
        for (int i = 3; i >= 0; i--) {
            bytes[(offset + i)] = ((byte) (value & 0xFF));
            value >>= 8;
        }
    }

    public static void toBigEndian(int value, byte[] bytes) {
        toBigEndian(value, bytes, 0);
    }

    public static byte[] toBigEndian(int value) {
        byte[] bytes = new byte[4];

        toBigEndian(value, bytes);

        return bytes;
    }

    public static void toBigEndian(long value, byte[] bytes, int offset) {
        for (int i = 7; i >= 0; i--) {
            bytes[(offset + i)] = ((byte) (int) (value & 0xFF));
            value >>= 8;
        }
    }

    public static void toBigEndian(long value, byte[] bytes) {
        toBigEndian(value, bytes, 0);
    }

    public static byte[] toBigEndian(long value) {
        byte[] bytes = new byte[8];

        toBigEndian(value, bytes);

        return bytes;
    }

    public static int intFromBigEndian(byte[] bytes) {
        int value = 0;
        int shift = 0;

        for (int i = 3; i >= 0; i--) {
            value |= (bytes[i] & 0xFF) << shift;
            shift += 8;
        }

        return value;
    }

    public static long longFromBigEndian(byte[] bytes) {
        long value = 0L;
        int shift = 0;

        for (int i = 7; i >= 0; i--) {
            value |= (bytes[i] & 0xFF) << shift;
            shift += 8;
        }

        return value;
    }

    public static long longFromLittleEndian(byte[] bytes) {
        long value = 0L;

        for (int i = 0; i < 8; i++) {
            value += ((bytes[i] & 0xFF) << 8 * i);
        }
        return value;
    }

    public static String toHex(byte b) {
        return toHex(new byte[]{b});
    }

    public static String toHex(byte[] bytes) {
        return DatatypeConverter.printHexBinary(bytes);
    }

    public static String toHex(String str)
            throws UnsupportedEncodingException {
        return toHex(toUtf8(str));
    }

    public static boolean isHex(String str) {
        String HEX = "1234567890ABCDEFabcdef";

        return Strings.containsOnly(str, "1234567890ABCDEFabcdef");
    }

    public static byte[] fromHex(String str) {
        if (str.length() % 2 != 0) {
            str = "0" + str;
        }

        return DatatypeConverter.parseHexBinary(str);
    }

    public static String stringFromHex(String str)
            throws UnsupportedEncodingException {
        return fromUtf8(fromHex(str));
    }

    public static String toBase64(byte[] bytes) {
        return Base64.encodeBase64URLSafeString(bytes);
    }

    public static String toBase64String(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }

    public static boolean isBase64(String str) {
        return Base64.isBase64(str);
    }

    public static byte[] fromBase64(String str) {
        return Base64.decodeBase64(str);
    }

    public static byte[] intToByteArray(final int integer) {
        int byteNum = (40 - Integer.numberOfLeadingZeros(integer < 0 ? ~integer : integer)) / 8;
        byte[] byteArray = new byte[2];

        for (int n = 0; n < byteNum; n++)
            byteArray[1 - n] = (byte) (integer >>> (n * 8));

        return byteArray;
    }


    public static int byteArrayToInt(byte[] b) {
        byte[] bytes = new byte[4];
        if (b.length < 4) {
            System.arraycopy(b, 0, bytes, 0, b.length);
        }
        return (bytes[3] & 0xFF) << 24 | (bytes[2] & 0xFF) << 16 | (bytes[1] & 0xFF) << 8 | bytes[0] & 0xFF;
    }

    public static byte[] toByteArray(String hexString) {
        hexString = hexString.replace(" ", "");
        int length = hexString.length() / 2;
        byte[] byteArray = new byte[length];
        for (int i = 0; i < length; i++) {
            byte high = (byte) Character.digit(hexString.charAt(2 * i), 16);
            byte low = (byte) Character.digit(hexString.charAt(2 * i + 1), 16);
            byteArray[i] = (byte) (high << 4 | low);
        }
        return byteArray;
    }

    public static final short setShort16(byte[] bArray, short bOff, short sValue) {
        bArray[bOff + 1] = (byte) (sValue >> 8);
        bArray[bOff + 0] = (byte) (sValue >> 0);
        return (short) (bOff + 2);
    }

    public static final short getShort(byte[] bArray, int bOff) {
        return (short) (((bArray[bOff + 1] << 8) | bArray[bOff + 0] & 0xff));
    }

    public static int byteToInt(byte b) {
        int i = b;
        i = b & 0xff;
        return i;
    }

    public static String getTransNoFromContext(String request) {
        JsonObject jsonObject = new JsonParser().parse(request).getAsJsonObject();
        JsonObject contextObject = jsonObject.getAsJsonObject("context");
        JsonElement transNoElement = contextObject.get("transNo");
        String transNo = transNoElement.getAsString();
        return transNo;
    }

    public static String getCurrentDate() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(new Date());
    }

    /**
     * get params info from request
     *
     * @param {String} request
     * @return {Map<String,Object>}
     */
    public static Map<String, Object> getInfoFromRequest(String request) {
        Map<String, Object> result = new HashMap<String, Object>();
        JsonObject jsonObject = new JsonParser().parse(request).getAsJsonObject();
        JsonObject contextJsonObject = jsonObject.getAsJsonObject("context");
        if(contextJsonObject.has("protocol")){
            result.put("protocol", contextJsonObject.get("protocol").getAsString());
        }
        result.put("transNo", contextJsonObject.get("transNo").getAsString());
        return result;
    }

    public static boolean isBase64url(String str) {
        boolean ret = Base64.isBase64(str);
        return !ret ? false : Strings.isBase64url(str);
    }

    public static byte[] strictBase64URLdecode(String str) {
        if (isBase64url(str)) {
            return Base64.decodeBase64(str);
        } else {
            throw new UAFRuntimeException(" string is not valid base64url encoded : " + str);
        }
    }

    public static void main(String[] args) {
//        byte[] certAuthTradeBase =null;
//        byte[] certAuthTradeIshow =null;
//        byte[] certAuthTradeShowdata =null;
//        byte[] data = Convert.fromBase64("AYpgAAKKPgB7CiAgInNob3dUZXh0IiA6ICLnoa7orqTmlK_ku5g5OC44OeS4hyIsCiAgInNob3dGbGFnIiA6ICIwMCIKfQOKAgAAAASKFADnoa7orqTmlK_ku5g5OC44OeS4hw");
//        ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
//        TLVTag p7DataTag = new TLVTag(TLVTag.readTag(buffer));//2字节标签
//        byte[] p7DataBytes = p7DataTag.parseByteArray(buffer);
//        ByteBuffer resBuffer = ByteBuffer.wrap(p7DataBytes).order(ByteOrder.LITTLE_ENDIAN);
//        while (resBuffer.hasRemaining()) {
//            byte[] tagByte = new byte[2];
//            resBuffer.get(tagByte);
//            int tag = Convert.byteArrayToInt(tagByte);
//            byte[] lenByte = new byte[2];
//            resBuffer.get(lenByte);
//            int len = Convert.byteArrayToInt(lenByte);
//            byte[] val = new byte[len];
//            resBuffer.get(val);
//            switch (tag) {
//                case 35330: {
//                    certAuthTradeBase = val;
//                    break;
//                }
//                case 35331: {
//                    certAuthTradeIshow = val;
//                    break;
//                }
//                case 35332: {
//                    certAuthTradeShowdata = val;
//                    break;
//                }
//            }
//        }
//        try {
//            System.out.println("b:"+new String(certAuthTradeBase,"utf-8"));
//            System.out.println("d:"+new String(certAuthTradeShowdata,"utf-8"));
//            System.out.println("bbase64:"+Convert.toBase64(certAuthTradeBase));
//            System.out.println("dbase64:"+Convert.toBase64(certAuthTradeShowdata));
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }

        String s = "AYpgAAKKPgB7CiAgInNob3dUZXh0IiA6ICLnoa7orqTmlK_ku5g5OC44OeS4hyIsCiAgInNob3dGbGFnIiA6ICIwMSIKfQOKAgABAASKFADnoa7orqTmlK_ku5g5OC44OeS4hw";
        System.out.println("sm3:" + Convert.toHex(SM3Utils.doSM3Hash(Convert.fromBase64(s))));
        System.out.println("sha256:" + Convert.toBase64(CryUtil.getSHA256(Convert.fromBase64(s))));

    }
}
